#include "../include/head.h"
//copy sb server_dir.c
int getsOpenfdCal[1024] = {0};
pthread_mutex_t getsOpenfdCal_mtx = PTHREAD_MUTEX_INITIALIZER;
int addOpenfdCal(int openfd)
{
    pthread_mutex_lock(&getsOpenfdCal_mtx);
    ++(getsOpenfdCal[openfd]);
    pthread_mutex_unlock(&getsOpenfdCal_mtx);
}
int delOpenfdCal(int openfd)
{
    pthread_mutex_lock(&getsOpenfdCal_mtx);
    --(getsOpenfdCal[openfd]);
    if((getsOpenfdCal[openfd]) ==0 )
    {
        close(openfd);
        printf("fd:%d closed\n");
    }
    pthread_mutex_unlock(&getsOpenfdCal_mtx);
}

int client_puts_comfirm(int target,int args_len,char *args,int netfd,char *now_path_buf)
{
    shareRes_t *upload_share = (shareRes_t *)malloc(sizeof(shareRes_t));

    char argbuf[2048]={0};
    memcpy(argbuf,args,args_len);
    char *addr1=strtok(argbuf," ");//客户端文件的地址
    char *addr2=strtok(NULL," ");//服务端要存储的文件的地址
    char *md5=strtok(NULL," ");
    char *filesizebuf=strtok(NULL," ");
    char *father_netfd = strtok(NULL, " ");
    char *user_id = strtok(NULL, " ");
    char *now_path_id = strtok(NULL, " ");

    off_t netfilesize = 0;

    struct stat file_stat;
    if (stat(addr1, &file_stat) == -1) {
        printf("server_puts_query stat error\n");
        return -1;
    }
    off_t filesize = file_stat.st_size;

    sscanf(filesizebuf,"%ld",&netfilesize);

    if(netfilesize == filesize)
    {
        printf("极速快传已完成！\n");
        return -1;
    }

    if(netfilesize != 0)
    {
        printf("指定路径下已有同名文件，是否继续？%ld\n",netfilesize);
        printf("请输入(0:取消 1:续写 2:覆写 ):");
        scanf("%d", &upload_share->client_choose);
        fflush(stdin);
    }
    else{
        upload_share->client_choose = 3;
    }

    upload_share->type = C_OP_PUTS_BEGIN;
    upload_share->args_len = args_len;
    upload_share->file_size = filesize;
    memcpy(upload_share->agrs, args, args_len);

    pthread_t tid1;
    pthread_create(&tid1, NULL, upload_enter, upload_share);
       
    // 分离线程（线程结束后自动回收资源）
    pthread_detach(tid1);

    return 1;
}

#define ALIGNMENT 4096
typedef struct
{
    char ipaddr[15];
    int port;
    off_t start;
    off_t size;
}dataServerAddress;
#define MIN(a, b) ((a) < (b) ? (a) : (b))
void calculate_chunks(off_t netfilesize, int num, dataServerAddress *chunks) {
   if (num <= 0 || netfilesize == 0 || !chunks) return false;

    uint64_t total_assigned = 0;
    uint64_t next_aligned_offset = 0;

    for (int i = 0; i < num; i++) {
        bool is_last_chunk = (i == num - 1);
        
        // 计算理论结束位置
        uint64_t theoretical_end = (netfilesize * (i + 1)) / num;
        
        // 对齐结束位置
        uint64_t aligned_end = ((theoretical_end + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
        aligned_end = MIN(aligned_end, netfilesize);
        
        // 最后一个块必须精确结束
        if (is_last_chunk) {
            aligned_end = netfilesize;
        }
        
        // 计算当前块大小
        chunks[i].start = next_aligned_offset;
        chunks[i].size = aligned_end - next_aligned_offset;
        
        // 更新状态
        total_assigned += chunks[i].size;
        next_aligned_offset = aligned_end;
        
        // 提前结束条件
        if (next_aligned_offset >= netfilesize) {
            num = i + 1;  // 调整实际分块数
            break;
        }
    }

    // 验证
    if (total_assigned != netfilesize) {
        fprintf(stderr, "Error: Total assigned size (%lu) != filesize (%lu)\n",
                total_assigned, netfilesize);
        return false;
    }

    return true;
}


int client_gets_comfirm(int target,int args_len,char *args,int netfd,char *now_path_buf)
{
    
    char argbuf[512]={0};
    memcpy(argbuf,args,args_len);
    char *addr1=strtok(argbuf," ");//客户端文件的地址
    char *addr2=strtok(NULL," ");//服务端要存储的文件的地址
    char *netfilesizebuf=strtok(NULL," ");
    char* md5 = strtok(NULL," ");

    char *father_netfd = strtok(NULL, " ");
    char *user_id = strtok(NULL, " ");
    char *now_path_id = strtok(NULL, " ");

    /*WP5 多点下载*/
    char *dataserver_num_buf = strtok(NULL," ");
    int dataserver_num = atoi(dataserver_num_buf);

    dataServerAddress* dsAddressArr = (dataServerAddress*)calloc(dataserver_num,sizeof(dataServerAddress));
    char* dataserver_ip_buf = NULL;
    char* dataserver_port_buf = NULL;
    for(int i = 0;i<dataserver_num;i++ )
    {
        dataserver_ip_buf = strtok(NULL," ");
        dataserver_port_buf = strtok(NULL," ");
        memcpy(dsAddressArr[i].ipaddr,dataserver_ip_buf,strlen(dataserver_ip_buf));
        dsAddressArr[i].port = atoi(dataserver_port_buf);
        dsAddressArr[i].size = 0;
        dsAddressArr[i].start = 0;
    }


    /*-----------*/
    off_t netfilesize = 0;
    sscanf(netfilesizebuf,"%ld",&netfilesize);

    calculate_chunks(netfilesize,dataserver_num,dsAddressArr);

    char *filename;
    char *fileFatherPath;
    split_path(addr1,&fileFatherPath,&filename);

    char localFilePath[512] = {0}; 
    if(addr2[strlen(addr2)-1]=='/')
    {
        sprintf(localFilePath,"%s%s",addr2,filename);
    }
    else
    {
        sprintf(localFilePath,"%s/%s",addr2,filename);
    }
    printf("%s %s %s %s\n", addr1, addr2, filename, localFilePath);
    // pause();


    off_t filesize = 0;
    // if(access(localFilePath,F_OK)!=-1)
    // {
    //     struct stat file_stat;
    //     if (stat(localFilePath, &file_stat) == -1) {
    //         //printf("server_gets_query open filePath = %s\n", filePath);
    //         //printf("server_puts_query 5 stat error\n");
    //         free(filename);
    //         free(fileFatherPath);
    //         return -1;
    //     }

    //     filesize = file_stat.st_size;
    //     printf("本地路径下存在同名文件: %s,是否继续?\n",localFilePath);
    //     if(filesize < netfilesize)
    //     {
    //         printf("请输入(0:取消 1:覆写 2:续写):");
    //         fflush(stdout);
    //         int userop;
    //         scanf("%d", &download_share->client_choose);
    //         if(&download_share->client_choose == 0)
    //         {
    //             printf("用户取消下载\n");
    //             free(filename);
    //             free(fileFatherPath);
    //             return -1;
    //         }
    //         if(download_share->client_choose != 0 &&download_share->client_choose != 1 &&download_share->client_choose != 2)
    //         {
    //             printf("输入错误！\n");
    //             free(filename);
    //             free(fileFatherPath);
    //             return -1;

    //         }
    //         fflush(stdin);
    //     }
    //     else
    //     {
    //         printf("请输入(0:取消 1:覆写):");
    //         fflush(stdout);
    //         scanf("%d",&download_share->client_choose);
    //         if(download_share->client_choose == 0)
    //         {
    //             printf("用户取消下载\n");
    //             free(filename);
    //             free(fileFatherPath);
    //             return -1;
    //         }
    //         if(download_share->client_choose != 0 &&download_share->client_choose != 1)
    //         {
    //             printf("输入错误！\n");
    //             free(filename);
    //             free(fileFatherPath);
    //             return -1;
    //         }
    //     }
    // }
    // else
    // {
    //     download_share->client_choose = 9;
    // }

    int open_fd = open(localFilePath,O_CREAT|O_RDWR,0666);
    addOpenfdCal(open_fd);
    //ftruncate(open_fd,netfilesize);

    shareRes_t *download_share_arr = (shareRes_t *)calloc(dataserver_num,sizeof(shareRes_t));
    for(int i = 0;i<dataserver_num;i++)
    {
        download_share_arr[i].client_choose = 9;
        download_share_arr[i].type = C_OP_GETS_BEGIN;
        download_share_arr[i].args_len = args_len;
        memcpy(download_share_arr[i].agrs, args, args_len);
        memcpy(download_share_arr[i].ip,dsAddressArr[i].ipaddr,strlen(dsAddressArr[i].ipaddr));
        download_share_arr[i].port = dsAddressArr[i].port;
        download_share_arr[i].file_size = dsAddressArr[i].start;
        download_share_arr[i].send_size = dsAddressArr[i].size;
        download_share_arr[i].open_fd = open_fd;
        addOpenfdCal(open_fd);
        pthread_t tid2;
        printf("创建子线程:%d offset: %ld size:%ld\n",i,dsAddressArr[i].start,dsAddressArr[i].size);
        pthread_create(&tid2, NULL, download_enter, &download_share_arr[i]);

        // 分离线程（线程结束后自动回收资源）
        pthread_detach(tid2);

    }
    
    delOpenfdCal(open_fd);
    free(filename);
    free(fileFatherPath);
    // printf("gets end\n");
    return 0;
}
